﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using ILRuntime.Runtime.Enviorment;
using UnityEngine.Networking;
using System.Threading.Tasks;
using ILRuntime.CLR.Method;
using ILRuntime.CLR.TypeSystem;
using Battle;
using UnityEngine.AddressableAssets;

namespace ILRuntime
{
    public static class ILRuntimeTools
    {
        private static string DLLPath_File => Application.dataPath+ "/Addressable/ILRuntime/ILRuntimeProject";
        private const string DLLPath_Addressables = "ILRuntimeProject";

        public const string HotFixMgrName = "ILRuntimeProject.MyHotFixMgr";
        public const string HotFixSettingName = "ILRuntimeProject.HotFixSetting";

        public static AppDomain AppDomainIns { get; private set; }
        private static System.IO.MemoryStream fs, p;

        private static IMethod method_GetSetting; 
        private static IMethod method_GetString;

        private static IMethod method_GetObj;

        public static string HotFixVersion { get; private set; }

        public static async Task<AppDomain> Init()
        {
            AppDomainIns = new AppDomain();

            Debug.Log("开始获取热更新文件");

            byte[] dll = await LoadFile_Addressables(DLLPath_Addressables + "_dll_res");
            Debug.Log("DLL 加载完毕  length:"+dll.Length);
            byte[] pdb = await LoadFile_Addressables(DLLPath_Addressables + "_pdb_res");
            Debug.Log("PDB 加载完毕  length:"+pdb.Length);

            //byte[] dll = LoadFile(DLLPath_File + ".dll");
            //byte[] dll = LoadFile(DLLPath_File + "_dll_res.txt");
            //byte[] dll = await LoadFile_WebRequest(DLLPath_File + ".dll");

            //byte[] pdb = LoadFile(DLLPath_File + ".pdb");
            //byte[] pdb = LoadFile(DLLPath_File + "_pdb_res.txt");
            //byte[] pdb = await LoadFile_WebRequest(DLLPath_File + ".pdb");

            fs = new System.IO.MemoryStream(dll);
            p = new System.IO.MemoryStream(pdb);

            try
            {
                AppDomainIns.LoadAssembly(fs, p, new ILRuntime.Mono.Cecil.Pdb.PdbReaderProvider());
                Debug.Log("AppDomain 加载程序集完毕");
            }
            catch
            {
                Debug.LogError("加载热更DLL失败");
            }

            InitializeILRuntime();
            InitMethod();

            return AppDomainIns;
        }

        #region dll 加载接口
        private static byte[] LoadFile(string path)
        {
            Debug.Log(path);
            return System.IO.File.ReadAllBytes(path);
        }
        private static async Task<byte[]> LoadFile_Addressables(string path)
        {
            Debug.Log(path);
            var text= await Addressables.LoadAssetAsync<TextAsset>(path).Task;
          
            return text.bytes;
        }
        private static async Task<byte[]> LoadFile_WebRequest(string path)
        {
            var request = UnityWebRequest.Get("file:///" + DLLPath_File );
            request.SendWebRequest();
            while (!request.isDone)
                await Task.Delay(200);
            if (!string.IsNullOrEmpty(request.error))
                Debug.LogError(request.error);
            byte[] bytes = request.downloadHandler.data;
            //销毁请求对象
            request.Dispose();

            return bytes;
        }
        #endregion

        private static void InitializeILRuntime()
        {
#if DEBUG && (UNITY_EDITOR || UNITY_ANDROID || UNITY_IPHONE)
            //由于Unity的Profiler接口只允许在主线程使用，为了避免出异常，需要告诉ILRuntime主线程的线程ID才能正确将函数运行耗时报告给Profiler
            AppDomainIns.UnityMainThreadID = System.Threading.Thread.CurrentThread.ManagedThreadId;
#endif
            //这里做一些ILRuntime的注册，这里我们对LitJson进行注册
            LitJson.JsonMapper.RegisterILRuntimeCLRRedirection(AppDomainIns);
            Debug.Log("LitJson 完成注册");

            //Debug.Log("现在我们来注册适配器, 该适配器由ILRuntime/Generate Cross Binding Adapter菜单命令自动生成");
            AppDomainIns.RegisterCrossBindingAdaptor(new LevelScriptAdaptor());
            AppDomainIns.RegisterCrossBindingAdaptor(new MyItemComponentAdaptor());

            //事件初始化
            AppDomainIns.DelegateManager.RegisterMethodDelegate<Battle.ST_EnemyDeathInfo>();

            //热更新域的初始化
            AppDomainIns.Invoke(HotFixMgrName, "StaticInit", null, null);

            HotFixVersion = AppDomainIns.Invoke(HotFixMgrName, "GetVersionInfo", null, null)?.ToString();
        }

        private static void InitMethod()
        {
            IType settingType = AppDomainIns.LoadedTypes[HotFixSettingName];
            method_GetSetting = settingType?.GetMethod("StaticGetSetting", 1);
            method_GetString = settingType?.GetMethod("StaticGetString", 1);

            IType mgrType = AppDomainIns.LoadedTypes[HotFixMgrName];
            method_GetObj = mgrType?.GetMethod("StaticGetHotFixObj", 1);
        }

        public static int GetHotFixSetting(string key)
        {
            if (method_GetSetting == null)
            {
                return -1;
            }

            using (var ctx = AppDomainIns.BeginInvoke(method_GetSetting))
            {
                ctx.PushObject(key);
                ctx.Invoke();
                int setting = ctx.ReadInteger();
                return setting;
            }
        }
        public static string GetHotFixString(string key)
        {
            if (method_GetString == null) return string.Empty;

            var obj = AppDomainIns.Invoke(method_GetString, null, new object[] { key });
            return obj.ToString();
        }

        public static object GetHotFixObj(string typeName)
        {
            if (method_GetObj == null) return string.Empty;

            var obj = AppDomainIns.Invoke(method_GetObj, null, new object[] { typeName });
            return obj;
        }

        public static void Destory()
        {
            if (fs != null)
            {
                fs.Close();
                fs = null;
            }
            if (p != null)
            {
                p.Close();
                p = null;
            }
        }
    }
}